package com.crl.rcdp.sys.service;

import com.cars.util.auth.AuthDTO;
import com.cars.util.bean.BasePage;
import com.cars.util.code.RandomCodeUtil;
import com.cars.util.global.AuthTypeEnum;
import com.cars.util.global.GlobalConst;
import com.cars.util.global.GlobalReturnCode;
import com.cars.util.json.JsonResult;
import com.cars.util.json.JsonResultUtil;
import com.cars.util.jwt.JwtResult;
import com.cars.util.jwt.JwtUtil;
import com.cars.util.list.ListUtils;
import com.cars.util.string.StringUtil;
import com.crl.rcdp.sys.dao.SysAppApiDao;
import com.crl.rcdp.sys.dao.SysAppDao;
import com.crl.rcdp.sys.dao.SysLoginLogDao;
import com.crl.rcdp.sys.dto.SysAppDTO;
import com.crl.rcdp.sys.dto.SysAppLoginDTO;
import com.crl.rcdp.sys.model.SysApp;
import com.crl.rcdp.sys.model.SysAppApi;
import com.crl.rcdp.sys.model.SysLoginLog;
import com.crl.rcdp.sys.vo.SysAppSearchVO;
import com.crl.redis.RedisKey;
import com.crl.redis.RedisUtil;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @description:
 * @author: 孔垂云
 * @version: 1.0
 * @date: 2020/7/12 11:24
 */
@Service
public class SysAppService {
    @Autowired
    private SysAppDao sysAppDao;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysAppApiDao sysAppApiDao;
    @Autowired
    private SysLoginLogDao sysLoginLogDao;

    /**
     * 获取所有接入应用
     */
    public BasePage<List<SysAppDTO>> page(SysAppSearchVO sysAppSearchVO) {
        BasePage<List<SysAppDTO>> basePage = new BasePage();
        int count = sysAppDao.count(sysAppSearchVO);
        basePage.setTotal(count);
        List<SysApp> list = sysAppDao.list(sysAppSearchVO);
        List<SysAppDTO> listResult = ListUtils.copyList(list, SysAppDTO.class);
        basePage.setData(listResult);
        return basePage;
    }

    /**
     * 新增
     */
    public int add(SysAppDTO sysAppDTO) {
        SysApp sysApp = new SysApp();
        BeanUtils.copyProperties(sysAppDTO, sysApp);
        //生成appid
        String appid = "crl" + RandomCodeUtil.createRandomNum(10).toLowerCase();
        sysApp.setAppid(appid);
        String appsecrect = UUID.randomUUID().toString();
        sysApp.setAppsecrect(appsecrect);
        //设置对应的api
        String apiIds = sysAppDTO.getApiIds();
        String[] apis = apiIds.split("@");
        for (String api : apis) {
            if (StringUtil.isNotNullOrEmpty(api) && !api.startsWith("T")) {
                SysAppApi sysAppApi = new SysAppApi();
                sysAppApi.setAppid(appid);
                sysAppApi.setApiId(Integer.parseInt(api));
                sysAppApiDao.add(sysAppApi);
            }
        }
        return sysAppDao.add(sysApp);
    }

    /**
     * 根据id修改
     */
    public int update(SysAppDTO sysAppDTO) {
        SysApp sysApp = new SysApp();
        BeanUtils.copyProperties(sysAppDTO, sysApp);
        sysAppDao.update(sysApp);
        sysAppApiDao.deleteByAppid(sysAppDTO.getAppid());
        //设置对应的api
        String apiIds = sysAppDTO.getApiIds();
        String[] apis = apiIds.split("@");
        for (String api : apis) {
            if (StringUtil.isNotNullOrEmpty(api) && !api.startsWith("T")) {
                SysAppApi sysAppApi = new SysAppApi();
                sysAppApi.setAppid(sysAppDTO.getAppid());
                sysAppApi.setApiId(Integer.parseInt(api));
                sysAppApiDao.add(sysAppApi);
            }
        }
        if (sysAppDTO.getAuthType() == 2) {//按照APPsecrect授权
            //获取当前用户对应的accessToken
            SysApp sysAppCurrent = sysAppDao.get(sysAppDTO.getAppid());
            if (sysAppCurrent != null) {
                String accessToken = sysAppCurrent.getAccessToken();
                if (StringUtil.isNotNullOrEmpty(accessToken)) {
                    redisUtil.del(RedisKey.AUTH_ACCESSTOKEN_KEY + accessToken);
                    this.getAuthDTO(accessToken);//设置权限
                }
            }
        } else if (sysAppDTO.getAuthType() == 3) {//按照appid授权
            redisUtil.del(RedisKey.AUTH_APPID_KEY + sysAppDTO.getAppid());
        }
        return 1;
    }


    /**
     * 删除
     */
    public int delete(String appid) {
        sysAppApiDao.deleteByAppid(appid);
        return sysAppDao.delete(appid);
    }

    /**
     * 根据资源id获取资源对象
     */
    public SysAppDTO get(String appid) {
        SysAppDTO sysAppDTO = new SysAppDTO();
        SysApp sysApp = sysAppDao.get(appid);
        if (sysApp != null) {
            BeanUtils.copyProperties(sysApp, sysAppDTO);
            List<SysAppApi> list = sysAppApiDao.listByAppid(appid);
            String apiIds = "";
            for (SysAppApi sysAppApi : list) {
                apiIds += sysAppApi.getApiId() + "@";
            }
            sysAppDTO.setApiIds(apiIds);
        }
        return sysAppDTO;
    }

    /**
     * 生成accessToken
     * 1、先判断appid和appsecrect是否匹配
     * 2、生成accessToken和refreshToken
     * 3、删除accessToken对应的redis值
     * 4、修改数据库对应的accessToken和refreshToken
     * 5、重新设值
     *
     * @return
     */
    public JsonResult createAccessToken(SysAppLoginDTO sysAppLoginDTO) {
        //加入到登录日志 TODO
        SysApp sysApp = sysAppDao.getBySecrect(sysAppLoginDTO.getAppid(), sysAppLoginDTO.getAppsecrect());
        SysLoginLog sysLoginLog = new SysLoginLog();      //加入登录日志表
        sysLoginLog.setLoginIp("127.0.0.1");
        sysLoginLog.setUsername(sysAppLoginDTO.getAppid());
        sysLoginLog.setAuthType(AuthTypeEnum.APPSECRECT.getValue());//授权方式
        sysLoginLogDao.add(sysLoginLog);
        if (sysApp == null) {
            return JsonResultUtil.error("appid或appsecrect错误");//账号密码错误
        } else {
            Map<String, String> map = new HashedMap<>();
            String accessToken = JwtUtil.generateJWT(GlobalConst.TOKEN_EXPIRED, sysApp.getAppid(), 0, AuthTypeEnum.APPSECRECT.getValue());
            String refreshToken = JwtUtil.generateJWT(GlobalConst.REFRESH_TOKEN_EXPIRED, sysApp.getAppid(), 0, AuthTypeEnum.APPSECRECT.getValue());
            map.put("accessToken", accessToken);
            map.put("refreshToken", refreshToken);
            //把历史的accesstoken从redis中删除
            if (StringUtil.isNotNullOrEmpty(sysApp.getAccessToken())) {
                redisUtil.del(RedisKey.AUTH_ACCESSTOKEN_KEY + sysApp.getAppid());
            }
            //修改数据库对应的accessToken和refreshToken
            sysAppDao.updateAccessToken(sysApp.getAppid(), accessToken);
            sysAppDao.updateRefreshToken(sysApp.getAppid(), refreshToken);
            //把token设置到redis中
            this.getAuthDTO(accessToken);
            return JsonResultUtil.ok(map);
        }
    }

    /**
     * refreshToken
     *
     * @return
     */
    public JsonResult refreshToken(String refreshToken) {
        JsonResult jsonResult;
        JwtResult jwtResult = JwtUtil.parseJWT(refreshToken);
        boolean isValid = jwtResult.isValid();
        // 校验refreshtoken是否有效
        if (isValid) {
            String username = jwtResult.getOwner();
            String accessToken = JwtUtil.generateJWT(GlobalConst.TOKEN_EXPIRED, username, 1, 1);
            Map<String, String> map = new HashMap<>(2);
            map.put("accessToken", accessToken);
            map.put("refreshToken", refreshToken);
            sysAppDao.updateAccessToken(username, accessToken);
            this.getAuthDTO(accessToken);
            jsonResult = JsonResultUtil.ok(map);
        } else {
            jsonResult = JsonResultUtil.error(GlobalReturnCode.INVALID_REFRESHTOKEN);
        }
        return jsonResult;
    }


    /**
     * 根据appid获取对应的api接口
     *
     * @param appid
     * @return
     */
    public List<SysAppApi> listApiByAppid(String appid) {
        return sysAppApiDao.listByAppid(appid);
    }

    /**
     * 获取appsecrect
     *
     * @param appid
     * @return
     */
    public String getAppsecrect(String appid) {
        SysApp sysApp = sysAppDao.get(appid);
        if (sysApp != null) {
            return sysApp.getAppsecrect();
        } else {
            return "";
        }
    }

    /**
     * 根据appid获取授权的urls
     *
     * @param appid
     * @return
     */
    public Map<String, String> getUrls(String appid) {
        List<SysAppApi> list = sysAppApiDao.listByAppid(appid);
        HashMap<String, String> map = new HashMap<>();
        for (SysAppApi sysAppApi : list) {
            if (StringUtil.isNotNullOrEmpty(sysAppApi.getUrl())) {
                map.put(sysAppApi.getUrl(), sysAppApi.getUrl());
            }
        }
        return map;
    }

    /**
     * 根据accessToken获取authDTO
     *
     * @param accessToken
     * @return
     */
    private AuthDTO getAuthDTO(String accessToken) {
        String appid = JwtUtil.getJWTOwner(accessToken);
        AuthDTO authDTO = redisUtil.get(RedisKey.AUTH_ACCESSTOKEN_KEY + appid, AuthDTO.class);
        if (authDTO == null) {
            authDTO = new AuthDTO();
            authDTO.setAuthType(AuthTypeEnum.APPSECRECT.getValue());
            authDTO.setToken(accessToken);
            //获取appid
            authDTO.setOwner(appid);
            SysAppDTO sysAppDTO = this.get(appid);
            authDTO.setValidDate(sysAppDTO.getValidDate());//有效日期
            authDTO.setStatus(sysAppDTO.getStatus());//是否禁用
            //获取urls
            authDTO.setUrls(this.getUrls(appid));
            List<String> listIPs = Arrays.asList(sysAppDTO.getIp().split(","));
            authDTO.setIps(listIPs);
            redisUtil.set(RedisKey.AUTH_ACCESSTOKEN_KEY + appid, authDTO);
        }
        return authDTO;
    }

    /**
     * 按照appid获取authDTO
     *
     * @param appid
     * @return
     */
    public AuthDTO getAuthDTOByAppid(String appid) {
        AuthDTO authDTO = redisUtil.get(RedisKey.AUTH_APPID_KEY + appid, AuthDTO.class);
        if (authDTO == null) {
            authDTO = new AuthDTO();
            //获取appid
            authDTO.setOwner(appid);
            SysApp sysApp = sysAppDao.get(appid);
            if (sysApp != null) {
                authDTO.setAuthType(AuthTypeEnum.APPID.getValue());
                authDTO.setValidDate(sysApp.getValidDate());//有效日期
                authDTO.setStatus(sysApp.getStatus());//是否禁用
                //获取urls
                authDTO.setUrls(this.getUrls(appid));
                List<String> listIPs = Arrays.asList(sysApp.getIp().split(","));
                authDTO.setIps(listIPs);
            }
            redisUtil.set(RedisKey.AUTH_APPID_KEY + appid, authDTO);
        }
        return authDTO;
    }
}
